package com.legendframework.core.ioc;

import com.legendframework.core.Store;
import com.legendframework.core.ioc.annotation.Bean;
import com.legendframework.core.ioc.annotation.Resource;
import com.legendframework.core.AbstractLegendPlugin;
import com.legendframework.core.dao.Return;

import java.lang.reflect.Method;
import java.util.LinkedHashMap;

public abstract class AbstractBeansGenerate implements BeansGenerate , BeanInstanceSuccessHandle {

    /**
     * 框架容器
     */
    protected Store store;


    public AbstractBeansGenerate(Store store) {
        this.store = store;
    }

    @Override
    public LinkedHashMap<String, Object> generate(Class<?> cls , AbstractLegendPlugin plugin) {
        synchronized (AbstractBeansGenerate.class){
            LinkedHashMap<String, Object> map = new LinkedHashMap<>();
            //先从容器中取Bean
            Return<String, Object> checkBean = null;
            try {
                checkBean = getBean(getBeanName(cls), cls);
            } catch (Throwable e) {
            }
            Return<String, Object> clsNewInstance;
            if (checkBean != null) {
                clsNewInstance = checkBean;
            } else {
                //没有则实例化
                clsNewInstance = newInstance(cls , plugin);
                clsNewInstance = store.getBeansFactory().toIoc(aop(clsNewInstance.getR2()), clsNewInstance.getR1());
                successHandle(clsNewInstance.getR1(), clsNewInstance.getR2() , plugin);
            }
            map.put(clsNewInstance.getR1(), clsNewInstance.getR2());
            //实体类中的方法方式构建
            for (Method declaredMethod : cls.getDeclaredMethods()) {
                if (!declaredMethod.isAnnotationPresent(Bean.class)) {
                    continue;
                }
                Return<String, Object> checkMethodBean = null;
                try {
                    Bean annotation = declaredMethod.getAnnotation(Bean.class);
                    checkMethodBean = getBean(annotation.value(), declaredMethod.getReturnType());
                } catch (Throwable e) {
                }
                Return<String, Object> methodNewInstance;
                if (checkMethodBean != null) {
                    methodNewInstance = checkMethodBean;
                } else {
                    //没有则构建
                    methodNewInstance = generateMethod(declaredMethod, clsNewInstance.getR2(),plugin);
                    if (methodNewInstance == null) {
                        continue;
                    }
                    successHandle(methodNewInstance.getR1(), methodNewInstance.getR2(),plugin);
                }
                map.put(methodNewInstance.getR1(), methodNewInstance.getR2());
            }
            return map;
        }
    }

    /**
     * 将这个字节码中的所有涉及到需要构建的对象构建出来
     *
     * @param cls class
     * @return
     */
    protected abstract Return<String, Object> newInstance(Class<?> cls , AbstractLegendPlugin plugin);

    /**
     * 将这个Method的返回值作为对象返回
     *
     * @param method 方法
     * @param obj    执行方法的对象
     * @return 方法的执行结果
     */
    protected abstract Return<String, Object> generateMethod(Method method, Object obj , AbstractLegendPlugin plugin);

    /**
     * 根据Class获取Ioc容器中的对象
     *
     * @param cls 字节码
     * @return
     */
    protected abstract Return<String, Object> getBean(String beanName, Class<?> cls);

    /**
     * 获取需要注入的Bean
     * <p>
     * 根据字节码获取对象，由于实例化类型是未确定的
     * 传入的class有可能是一个接口或者一个抽象类
     *
     * @param cls      字节码
     * @param resource 注入Bean的参数
     * @return
     */
    protected abstract Object getBeanByUndeterminedType(Class<?> cls, Resource resource ,AbstractLegendPlugin plugin);

    /**
     * 对实例化对象进行切面
     * @param obj 实例化对象
     * @return
     */
    protected abstract <T> T aop(T obj);
}
